package pl.elka.pobr.ppr.logic.recognition;

import java.util.Iterator;
import java.util.Vector;

import pl.elka.pobr.ppr.logic.Coord;
import pl.elka.pobr.ppr.logic.ObjectType;
import pl.elka.pobr.ppr.logic.Pixel;
import pl.elka.pobr.ppr.utils.Log;

public class Recognizer {

    private static final double SYMBOL_PROBABILITY_COUNT_55 = 0.55;
    private static final double SYMBOL_PROBABILITY_COUNT_75 = 0.75;
    private static final String LOG_TAG = "Recognizer";
    // label vertically values
    private static final double[] l_moments = {-1, 0.3080717378242511, 0.044756624117926115, 0.005125770198290851,
            7.193086063894788E-4, 9.514504371601326E-7, 1.0132229929156685E-4, 0.012537892882032001, -5.508076989876715E-4,
            -2.7584097206359453E-5, 5.0283665917823386E-8};
    private static final double[] e_moments = {-1, 0.25223067628757373, 0.017831014075153574, 1.2289922692648408E-4,
            4.166568983131068E-5, -2.981455337780902E-9, -5.490025021451464E-6, 0.01144732499633331, -1.0154192136896672E-5,
            5.482716206829574E-7, 7.330395675083314E-10};
    private static final double[] c_moments = {-1, 0.3051903652464595, 0.020414109646129015, 0.00503691161424387,
            9.360426025194945E-4, -1.930470745247013E-6, -1.2720432436237608E-4, 0.018181762348284586, -5.126086264655469E-4,
            -2.3534680619727355E-5, 3.2798486498267936E-7};
    private static final double[] h_moments = {-1, 0.22623570744848223, 9.841860517032771E-5, 3.8922049303197145E-7,
            4.5413870485552694E-8, -3.260497771427206E-15, 1.502829286112841E-10, 0.012771044179886226, -4.297582781830233E-8,
            -8.775848947640836E-9, 8.2598673774446E-17};
    private static final double[] s_moments = {-1, 0.16647127712303908, 8.160884375829489E-5, 3.894247605997468E-8,
            1.6732118796578575E-8, 3.91114787292667E-18, 1.3931260463803066E-10, 0.006907769315804345, -2.776294657924513E-9,
            -8.861512125437923E-10, 3.240368745549277E-17};
    private static final MomentsStorage[] PATTERNS = {new MomentsStorage(1.3769, 0.1458, 0.1931, l_moments),
            new MomentsStorage(1.4523, 0.1855, 0.1611, e_moments), new MomentsStorage(1.4632, 0.0494, 0.1777, c_moments),
            new MomentsStorage(1.9949, 0.1713, 0.1138, h_moments), new MomentsStorage(1.5974, 0.1202, 0.1286, s_moments)};
    private Vector<Segment> mSegments;
    private boolean[][] mBitmapPx;
    private Pixel[][] mRealBitmap;
    private Pixel[][] mOriginalBitmap;
    private Vector<LechSymbol> mSymbols;

    public Recognizer(Vector<Segment> segments, boolean[][] bitmapPixels, Pixel[][] originalImg) {
        mSegments = segments;
        mBitmapPx = bitmapPixels;
        mOriginalBitmap = originalImg;
        mRealBitmap = new Pixel[mBitmapPx.length][mBitmapPx[0].length];
        mSymbols = new Vector<LechSymbol>();
    }

    public void recognize() {
        for (Iterator<Segment> iter = mSegments.iterator(); iter.hasNext();) {
            Segment seg = iter.next();
            compareWithPatterns(seg);
        }
        removeNotImportantSegments();
        removeAloneSegments();
        findSymbols();
        markSymbolsOnOriginalPicture();
    }

    private void markSymbolsOnOriginalPicture() {
        for (Iterator<LechSymbol> iterator = mSymbols.iterator(); iterator.hasNext();) {
            LechSymbol sym = iterator.next();
            Vector<Segment> symbolSegments = sym.getSymbolSegmentsVector();
            int top = 10000;
            int bottom = -1;
            int left = 10000;
            int right = -1;
            for (Iterator<Segment> iterator2 = symbolSegments.iterator(); iterator2.hasNext();) {
                Segment seg = iterator2.next();
                if (seg.getType() == ObjectType.ROUND_SYMBOL) {
                    int[] t = MomentsComputer.findMinAndMax(seg.getPixels());
                    if (t[0] < left) {
                        left = t[0];
                    }
                    if (t[1] > right) {
                        right = t[1];
                    }
                    if (t[2] < top) {
                        top = t[2];
                    }
                    if (t[3] > bottom) {
                        bottom = t[3];
                    }
                }
                if (seg.getType() == ObjectType.LETTER_C) {
                    int[] t = MomentsComputer.findMinAndMax(seg.getPixels());
                    if (t[0] < left) {
                        left = t[0];
                    }
                    if (t[1] > right) {
                        right = t[1];
                    }
                    if (t[2] < top) {
                        top = t[2];
                    }
                    if (t[3] > bottom) {
                        bottom = t[3];
                    }
                }
                if (seg.getType() == ObjectType.LETTER_E) {
                    int[] t = MomentsComputer.findMinAndMax(seg.getPixels());
                    if (t[0] < left) {
                        left = t[0];
                    }
                    if (t[1] > right) {
                        right = t[1];
                    }
                    if (t[2] < top) {
                        top = t[2];
                    }
                    if (t[3] > bottom) {
                        bottom = t[3];
                    }
                }
                if (seg.getType() == ObjectType.LETTER_L) {
                    int[] t = MomentsComputer.findMinAndMax(seg.getPixels());
                    if (t[0] < left) {
                        left = t[0];
                    }
                    if (t[1] > right) {
                        right = t[1];
                    }
                    if (t[2] < top) {
                        top = t[2];
                    }
                    if (t[3] > bottom) {
                        bottom = t[3];
                    }
                }
            }
            // default is RED
            int r = 255;
            int g = 0;
            int b = 0;
            if (sym.getProbability() < SYMBOL_PROBABILITY_COUNT_75) {
                // for <0.75 items is YELLOW
                r = 255;
                g = 242;
                b = 0;
            }
            if (sym.getProbability() < SYMBOL_PROBABILITY_COUNT_55) {
                // for 0.55 items is LIGHT_BLUE
                r = 18;
                g = 237;
                b = 237;
            }
            for (int x = 0; x < right - left; ++x) {
                mOriginalBitmap[left + x][top] = new Pixel(r, g, b);
                mOriginalBitmap[left + x][bottom] = new Pixel(r, g, b);
            }
            for (int y = 0; y < bottom - top; ++y) {
                mOriginalBitmap[left][top + y] = new Pixel(r, g, b);
                mOriginalBitmap[right][top + y] = new Pixel(r, g, b);
            }
            Log.d(LOG_TAG, ">> Symbol probability = " + sym.getProbability());
        }
    }

    private void findSymbols() {
        Log.d(LOG_TAG, ">> findSymbols()");
        Vector<Integer> alreadyCheckedSegmentIds = new Vector<Integer>(); // already used segments
        for (Iterator<Segment> iterator = mSegments.iterator(); iterator.hasNext();) {
            Segment seg = iterator.next();
            if (isThisIdUsed(seg.getSegId(), alreadyCheckedSegmentIds)) {
                continue;
            }
            // assume each symbol must have round symbol and letters H + C
            if (seg.getType() == ObjectType.LETTER_H) {
                Log.d(LOG_TAG, ">> H");
                int wx = seg.getWeightCX();
                int wy = seg.getWeightCY();
                int sizeSeg = seg.getCircumscribedRectangleArea();
                int maxDiameter = seg.getMaxDiameter();
                LechSymbol symbol = new LechSymbol();
                symbol.addSegment(seg);
                alreadyCheckedSegmentIds.add(seg.getSegId());
                // find round symbol
                for (Iterator<Segment> iterator2 = mSegments.iterator(); iterator2.hasNext();) {
                    Segment seg2 = iterator2.next();
                    if (seg.getSegId() != seg2.getSegId()) {
                        if (seg2.getType() == ObjectType.ROUND_SYMBOL) {
                            Log.d(LOG_TAG, ">> SYM");
                            int wx2 = seg2.getWeightCX();
                            int wy2 = seg2.getWeightCY();
                            double dist2 = Math.sqrt(Math.pow(wx - wx2, 2) + Math.pow(wy - wy2, 2));
                            if (dist2 < 2 * maxDiameter) {
                                Log.d(LOG_TAG, ">> found SYM + H");
                                // found SYM + H
                                symbol.addSegment(seg2);
                                alreadyCheckedSegmentIds.add(seg2.getSegId());
                                break;
                            }
                        }
                    }
                }
                // find letter C
                for (Iterator<Segment> iterator2 = mSegments.iterator(); iterator2.hasNext();) {
                    Segment seg2 = iterator2.next();
                    if (seg.getSegId() != seg2.getSegId()) {
                        if (seg2.getType() == ObjectType.LETTER_C) {
                            Log.d(LOG_TAG, ">> C");
                            int wx2 = seg2.getWeightCX();
                            int wy2 = seg2.getWeightCY();
                            double dist2 = Math.sqrt(Math.pow(wx - wx2, 2) + Math.pow(wy - wy2, 2));
                            int sizeSeg2 = seg2.getCircumscribedRectangleArea();
                            if (dist2 < 2 * maxDiameter && (Math.abs(sizeSeg - sizeSeg2) < sizeSeg * 0.5)) {
                                Log.d(LOG_TAG, ">> found H + C");
                                // found H + C
                                symbol.addSegment(seg2);
                                alreadyCheckedSegmentIds.add(seg2.getSegId());
                                // now find neighbours of letter C
                                for (Iterator<Segment> ii = mSegments.iterator(); ii.hasNext();) {
                                    Segment sE = ii.next();
                                    if (isThisIdUsed(sE.getSegId(), alreadyCheckedSegmentIds)) {
                                        continue;
                                    }
                                    if (sE.getType() == ObjectType.LETTER_E) {
                                        Log.d(LOG_TAG, ">> E");
                                        int wxE = sE.getWeightCX();
                                        int wyE = sE.getWeightCY();
                                        double distE = Math.sqrt(Math.pow(wx2 - wxE, 2) + Math.pow(wy2 - wyE, 2));
                                        int sizeSegE = sE.getCircumscribedRectangleArea();
                                        if (distE < 2 * maxDiameter && (Math.abs(sizeSeg2 - sizeSegE) < sizeSeg2 * 0.25)) {
                                            Log.d(LOG_TAG, ">> found C -> E");
                                            // found C -> E
                                            symbol.addSegment(sE);
                                            alreadyCheckedSegmentIds.add(sE.getSegId());
                                            // now find neighbours of letter E
                                            for (Iterator<Segment> iii = mSegments.iterator(); iii.hasNext();) {
                                                Segment sL = iii.next();
                                                if (isThisIdUsed(sL.getSegId(), alreadyCheckedSegmentIds)) {
                                                    continue;
                                                }
                                                if (sL.getType() == ObjectType.LETTER_L) {
                                                    Log.d(LOG_TAG, ">> L");
                                                    int wxL = sL.getWeightCX();
                                                    int wyL = sL.getWeightCY();
                                                    double distL = Math.sqrt(Math.pow(wxE - wxL, 2) + Math.pow(wyE - wyL, 2));
                                                    int sizeSegL = sL.getCircumscribedRectangleArea();
                                                    if (distL < 2 * maxDiameter
                                                            && (Math.abs(sizeSegE - sizeSegL) < sizeSegE * 0.25)) {
                                                        Log.d(LOG_TAG, ">> found E -> L");
                                                        // found C -> E
                                                        symbol.addSegment(sL);
                                                        alreadyCheckedSegmentIds.add(sL.getSegId());
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                // ended finding SYM + H + C and additionally neighbours of C
                                break;
                            }
                        }
                    }
                }
                Log.d(LOG_TAG, ">> symbol.getCount()=" + symbol.getCount());
                if (symbol.getCount() >= 3) {
                    double totalProb = 0;
                    for (Iterator<Segment> iterator2 = symbol.getSymbolSegmentsVector().iterator(); iterator2.hasNext();) {
                        Segment se = iterator2.next();
                        Log.d(LOG_TAG, ">> symbol type=" + se.getType() + ", probability=" + se.getProbability());
                        totalProb += se.getProbability();
                    }
                    totalProb += symbol.getCount() * 0.02;
                    totalProb /= symbol.getCount();
                    if (totalProb > 1) {
                        totalProb = 1.0;
                    }
                    symbol.setProbability(totalProb);
                    mSymbols.add(symbol);
                }
            }
        }
    }

    private boolean isThisIdUsed(int id, Vector<Integer> ids) {
        for (Iterator<Integer> iterator = ids.iterator(); iterator.hasNext();) {
            Integer integer = iterator.next();
            if (integer == id) {
                return true;
            }
        }
        return false;
    }

    private void removeNotImportantSegments() {
        Vector<Integer> segIds = new Vector<Integer>();
        for (Iterator<Segment> iterator = mSegments.iterator(); iterator.hasNext();) {
            Segment seg = iterator.next();
            if (seg.getType() == ObjectType.NOT_INTERESTING) {
                segIds.add(new Integer(seg.getSegId()));
            }
        }
        for (Iterator<Integer> iterator = segIds.iterator(); iterator.hasNext();) {
            removeSegment(iterator.next().intValue(), mBitmapPx);
        }
    }

    private void removeAloneSegments() {
        Vector<Integer> segIds = new Vector<Integer>();
        for (Iterator<Segment> iterator = mSegments.iterator(); iterator.hasNext();) {
            Segment seg = iterator.next();
            int wx = seg.getWeightCX();
            int wy = seg.getWeightCY();
            int[] mm = MomentsComputer.findMinAndMax(seg.getPixels());
            int diameterX = mm[1] - mm[0];
            int diameterY = mm[3] - mm[2];
            int maxDiameter = Math.max(diameterX, diameterY);
            boolean removeSegment = true;
            for (Iterator<Segment> iterator2 = mSegments.iterator(); iterator2.hasNext();) {
                Segment seg2 = iterator2.next();
                if (seg.getSegId() != seg2.getSegId()) {
                    int wx2 = seg2.getWeightCX();
                    int wy2 = seg2.getWeightCY();
                    double dist2 = Math.sqrt(Math.pow(wx - wx2, 2) + Math.pow(wy - wy2, 2));
                    if (dist2 < 2 * maxDiameter) {
                        removeSegment = false;
                        break;
                    }
                }
            }
            if (removeSegment) {
                segIds.add(new Integer(seg.getSegId()));
            }
        }
        for (Iterator<Integer> iterator = segIds.iterator(); iterator.hasNext();) {
            removeSegment(iterator.next().intValue(), mBitmapPx);
        }
    }

    private void removeSegment(int segId, boolean[][] pic) {
        for (Iterator<Segment> it = mSegments.iterator(); it.hasNext();) {
            Segment seg = it.next();
            if (seg.getSegId() == segId) {
                Vector<Coord> px = seg.getPixels();
                for (Iterator<Coord> iterator2 = px.iterator(); iterator2.hasNext();) {
                    Coord coord = iterator2.next();
                    pic[coord.x][coord.y] = false; // remove pixel from source bitmap
                }
                it.remove();
                break;
            }
        }
    }

    public Pixel[][] getOriginalBitmap() {
        return mOriginalBitmap;
    }

    public Pixel[][] getRealBitmap() {
        int w = mBitmapPx.length;
        int h = mBitmapPx[0].length;
        for (int y = 0; y < h; ++y) {
            for (int x = 0; x < w; ++x) {
                if (mBitmapPx[x][y]) {
                    mRealBitmap[x][y] = new Pixel(255, 255, 255);
                } else {
                    mRealBitmap[x][y] = new Pixel(0, 0, 0);
                }
            }
        }
        colorizeAll();
        return mRealBitmap;
    }

    private void colorizeSegment(Segment s, int colorVal) {
        // R, G, B, zolty, blekit, szary ---> L, E, C, H, SYM, N/A
        int[][] colors = {{255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0}, {0, 255, 255}, {128, 128, 128}};
        Vector<Coord> cs = s.getPixels();
        for (Iterator<Coord> iterator = cs.iterator(); iterator.hasNext();) {
            Coord c = iterator.next();
            mRealBitmap[c.x][c.y] = new Pixel(colors[colorVal][0], colors[colorVal][1], colors[colorVal][2]);
        }
    }

    private void colorizeAll() {
        for (Iterator<Segment> it = mSegments.iterator(); it.hasNext();) {
            Segment seg = it.next();
            colorizeSegment(seg, seg.getType().ordinal());
        }
    }

    private void compareWithPatterns(Segment segment) {
        Log.d(LOG_TAG, ">> compareWithPatterns()");
        segment.printValues();
        double[] probabilities = new double[5]; // probabilities for each single symbol
        MomentsStorage s = segment.getMoments();
        // //////////////////////////////////////////////// check if L
        Log.d(LOG_TAG, ">>>>>>>>>>>>>>>>>>>> check L");
        Log.d(LOG_TAG, "s.M[3]=" + s.M[3]);
        if (s.M[3] > 0.001) {
            probabilities[0] = Math.abs(s.M[3] - l_moments[3]) / Math.abs(l_moments[3]);
            if (probabilities[0] > 1) {
                probabilities[0] = 0.9;
            }
            Log.d(LOG_TAG, "s.M[7]=" + s.M[7]);
            if (s.M[7] > 0.009 && s.M[7] < 0.016) {
                probabilities[1] = Math.abs(s.M[7] - l_moments[7]) / (0.016 - 0.009);
                Log.d(LOG_TAG, "s.W3=" + s.W3);
                if (s.W3 > 0.3 && s.W3 < 1.67) {
                    probabilities[2] = Math.abs(s.W3 - PATTERNS[0].W3) / (1.67 - 0.3);
                    Log.d(LOG_TAG, "s.W7_Lp1=" + s.W7_Lp1);
                    if (s.W7_Lp1 > 0.04 && s.W7_Lp1 < 0.2) {
                        probabilities[3] = Math.abs(s.W7_Lp1 - PATTERNS[0].W7_Lp1) / (0.2 - 0.04);
                        Log.d(LOG_TAG, "s.W8_Lp2=" + s.W8_Lp2);
                        if (s.W8_Lp2 > 0.16 && s.W8_Lp2 < 0.32) {
                            probabilities[4] = Math.abs(s.W8_Lp2 - PATTERNS[0].W8_Lp2) / (0.32 - 0.16);
                            if (s.M[5] > 0) {
                                Log.d(LOG_TAG, "LETTER_L !!!");
                                segment.setType(ObjectType.LETTER_L);
                                double totalProb = 0;
                                for (int i = 0; i < probabilities.length; ++i) {
                                    totalProb += probabilities[i];
                                }
                                segment.setProbability(1 - totalProb / (probabilities.length + 1));
                                colorizeSegment(segment, 0);
                                return;
                            }
                        }
                    }
                }
            }
        }
        Log.d(LOG_TAG, "<<<<<<<<<<<<<<<<<<<<");
        // //////////////////////////////////////////// check if C
        Log.d(LOG_TAG, ">>>>>>>>>>>>>>>>>>>>  check C");
        Log.d(LOG_TAG, "s.W7_Lp1=" + s.W7_Lp1);
        if (s.W7_Lp1 > 0.02 && s.W7_Lp1 < 0.17) {
            probabilities[0] = Math.abs(s.W7_Lp1 - PATTERNS[2].W7_Lp1) / (0.17 - 0.02);
            Log.d(LOG_TAG, "s.W8_Lp2=" + s.W8_Lp2);
            if (s.W8_Lp2 > 0.14 && s.W8_Lp2 < 0.33) {
                probabilities[1] = Math.abs(s.W8_Lp2 - PATTERNS[2].W8_Lp2) / (0.33 - 0.14);
                Log.d(LOG_TAG, "s.M[1]=" + s.M[1]);
                if (s.M[1] > 0.25 && s.M[1] < 0.355) {
                    probabilities[2] = Math.abs(s.M[1] - c_moments[1]) / (0.355 - 0.25);
                    Log.d(LOG_TAG, "s.M[2]=" + s.M[2]);
                    if (s.M[2] > 0.001 && s.M[2] < 0.04) {
                        probabilities[3] = Math.abs(s.M[2] - c_moments[2]) / (0.04 - 0.001);
                        Log.d(LOG_TAG, "s.M[3]=" + s.M[3]);
                        if (s.M[3] > 0.0025 && s.M[3] < 0.010) {
                            probabilities[4] = Math.abs(s.M[3] - c_moments[3]) / (0.010 - 0.0025);
                            if (s.M[5] < 0) {
                                Log.d(LOG_TAG, "LETTER_C !!!");
                                segment.setType(ObjectType.LETTER_C);
                                double totalProb = 0;
                                for (int i = 0; i < probabilities.length; ++i) {
                                    totalProb += probabilities[i];
                                }
                                segment.setProbability(1 - totalProb / (probabilities.length + 1));
                                colorizeSegment(segment, 2);
                                return;
                            }
                        }
                    }
                }
            }
        }
        Log.d(LOG_TAG, "<<<<<<<<<<<<<<<<<<<<");
        // ////////////////////////////////////////////// check if E
        Log.d(LOG_TAG, ">>>>>>>>>>>>>>>>>>>> check E");
        Log.d(LOG_TAG, "s.W7_Lp1=" + s.W7_Lp1);
        if (s.W7_Lp1 > 0.04 && s.W7_Lp1 < 0.21) {
            probabilities[0] = Math.abs(s.W7_Lp1 - PATTERNS[1].W7_Lp1) / (0.21 - 0.04);
            Log.d(LOG_TAG, "s.M[1]=" + s.M[1]);
            if (s.M[1] > 0.21 && s.M[1] < 0.29) {
                probabilities[1] = Math.abs(s.M[1] - e_moments[1]) / (0.29 - 0.21);
                Log.d(LOG_TAG, "s.M[2]=" + s.M[2]);
                if (s.M[2] > 0.004 && s.M[2] < 0.04) {
                    probabilities[2] = Math.abs(s.M[2] - e_moments[2]) / (0.04 - 0.004);
                    Log.d(LOG_TAG, "s.M[4]=" + s.M[4]);
                    if (s.M[4] > 3.1E-5 && s.M[4] < 2.7E-4) {
                        probabilities[3] = Math.abs(s.M[4] - e_moments[4]) / (2.7E-4 - 3.1E-5);
                        Log.d(LOG_TAG, "s.M[7]=" + s.M[7]);
                        if (s.M[7] > 0.009 && s.M[7] < 0.013) {
                            probabilities[4] = Math.abs(s.M[7] - e_moments[7]) / (0.013 - 0.009);
                            Log.d(LOG_TAG, "LETTER_E !!!");
                            segment.setType(ObjectType.LETTER_E);
                            double totalProb = 0;
                            for (int i = 0; i < probabilities.length; ++i) {
                                totalProb += probabilities[i];
                            }
                            segment.setProbability(1 - totalProb / probabilities.length);
                            colorizeSegment(segment, 1);
                            return;
                        }
                    }
                }
            }
        }
        Log.d(LOG_TAG, "<<<<<<<<<<<<<<<<<<<<");
        // ////////////////////////////////////////////// check if H
        Log.d(LOG_TAG, ">>>>>>>>>>>>>>>>>>>> check H");
        Log.d(LOG_TAG, "s.W7_Lp1=" + s.W7_Lp1);
        if (s.W7_Lp1 < 0.185) {
            probabilities[0] = Math.abs(s.W7_Lp1 - PATTERNS[3].W7_Lp1) / Math.abs(PATTERNS[3].W7_Lp1);
            if (probabilities[0] > 1) {
                probabilities[0] = 0.9;
            }
            Log.d(LOG_TAG, "s.W8_Lp2=" + s.W8_Lp2);
            if (s.W8_Lp2 > 0.10 && s.W8_Lp2 < 0.21) {
                probabilities[1] = Math.abs(s.W8_Lp2 - PATTERNS[3].W8_Lp2) / (0.21 - 0.10);
                Log.d(LOG_TAG, "s.M[3]=" + s.M[3]);
                if (s.M[3] < 1.5E-4) {
                    probabilities[2] = Math.abs(s.M[3] - h_moments[3]) / Math.abs(h_moments[3]);
                    if (probabilities[2] > 1) {
                        probabilities[2] = 0.9;
                    }
                    Log.d(LOG_TAG, "s.M[7]=" + s.M[7]);
                    if (s.M[7] > 0.009 && s.M[7] < 0.016) {
                        probabilities[3] = Math.abs(s.M[7] - h_moments[7]) / (0.016 - 0.009);
                        Log.d(LOG_TAG, "s.W3=" + s.W3);
                        if (s.W3 > 0.55 && s.W3 < 2.2) {
                            probabilities[4] = Math.abs(s.W3 - PATTERNS[3].W3) / (2.2 - 0.55);
                            Log.d(LOG_TAG, "LETTER_H !!!");
                            segment.setType(ObjectType.LETTER_H);
                            double totalProb = 0;
                            for (int i = 0; i < probabilities.length; ++i) {
                                totalProb += probabilities[i];
                            }
                            segment.setProbability(1 - totalProb / probabilities.length);
                            colorizeSegment(segment, 3);
                            return;
                        }
                    }
                }
            }
        }
        Log.d(LOG_TAG, "<<<<<<<<<<<<<<<<<<<<");
        // ////////////////////////////////////////////// check if SYMBOL
        Log.d(LOG_TAG, ">>>>>>>>>>>>>>>>>>>> check SYMBOL");
        Log.d(LOG_TAG, "s.M[1]=" + s.M[1]);
        if (s.M[1] > 0.155 && s.M[1] < 0.21) {
            probabilities[0] = Math.abs(s.M[1] - s_moments[1]) / (0.21 - 0.155);
            Log.d(LOG_TAG, "s.M[7]=" + s.M[7]);
            if (s.M[7] > 0.006 && s.M[7] < 0.0099) {
                probabilities[1] = Math.abs(s.M[7] - s_moments[7]) / (0.0099 - 0.006);
                Log.d(LOG_TAG, "s.M[2]=" + s.M[2]);
                if (s.M[2] < 0.002) {
                    probabilities[2] = Math.abs(s.M[2] - s_moments[2]) / Math.abs(s_moments[2]);
                    if (probabilities[2] > 1) {
                        probabilities[2] = 0.9;
                    }
                    Log.d(LOG_TAG, "s.M[3]=" + s.M[3]);
                    if (s.M[3] < 7.0E-5) {
                        probabilities[3] = Math.abs(s.M[3] - s_moments[3]) / Math.abs(s_moments[3]);
                        if (probabilities[3] > 1) {
                            probabilities[3] = 0.9;
                        }
                        Log.d(LOG_TAG, "s.W8_Lp2=" + s.W8_Lp2);
                        if (s.W8_Lp2 > 0.05 && s.W8_Lp2 < 0.29) {
                            probabilities[4] = Math.abs(s.W8_Lp2 - PATTERNS[4].W8_Lp2) / (0.29 - 0.05);
                            Log.d(LOG_TAG, "SYMBOL !!!");
                            segment.setType(ObjectType.ROUND_SYMBOL);
                            double totalProb = 0;
                            for (int i = 0; i < probabilities.length; ++i) {
                                totalProb += probabilities[i];
                            }
                            segment.setProbability(1 - totalProb / probabilities.length);
                            colorizeSegment(segment, 4);
                            return;
                        }
                    }
                }
            }
        }
        Log.d(LOG_TAG, "<<<<<<<<<<<<<<<<<<<<");
    }
}
